Skip to content

最好的代码是没有 Bug 的代码,但最好的程序员是知道如何快速找到 Bug 的程序员。如何高效地定位和解决它们,是每个程序员都需要掌握的技能。下面是介绍一些定位 Bug 的小技巧。

巧用 Git bisect

程序员的噩梦是什么?

"这个 Bug 上周还没出现,到底是谁改的代码?!"

在多人开发项目时,难免会出现这种尴尬的情况,但如何在众多的 Commit 中找到已发问题的元凶?以前的我真的遇到过,然后人肉排查,手动通过二分法去找到那条错误的 Commit, 过程很痛苦、因为不仅要分析还要手动记录。

但 git bisect 可以帮助我们快速定位 bug,告别人肉排查。

什么是 git bisect

git bisect 是 Git 提供的一个用于快速定位代码库中引入错误(Bug)的特定提交的工具。基于二分查找算法,通过自动在提交历史中切换版本,帮助开发者高效缩小问题范围,最终找到导致问题的第一个错误提交。

实操步骤:

如下图的 Git 可视化工具显示的定位记录

img

启动"侦探模式"

bash
git bisect start          # 进入bisect时空隧道  
git bisect bad            # 标记当前版本有问题  
git bisect good b31b261   # 标记已知正常的提交(替换为你的正常commit哈希)

测试当前版本

Git 会自动跳转到中间的 Commit ,然后使用脚本 or 单元测试 or 人工测试 判断此时的 Commit 是否有问题

有问题:标记为 bad

bash
git bisect bad

正常:标记为 good

bash
git bisect good

重复直到破案

bash
[c380b68d90fdcc2f9b9d84858a0da4c66181a028] commit message

退出"时空隧道"

bash
git bisect reset  # 回到最初的分支

高级用法

执行自动化二分查找

bash
# 进入 bisect 模式
git bisect start

# 标记当前提交为"坏"(通常是 HEAD)
git bisect bad

# 标记已知的"好"提交(替换为你的正常版本哈希)
git bisect good b31b261

# 启动自动化测试脚本
git bisect run ./test-script.sh

git bisect reset  # 回到最初的分支

脚本需要满足以下条件:

返回值规则

  • 返回 0:当前提交是"好"的(无 Bug)
  • 返回非 0(如 1):当前提交是"坏"的(有 Bug)
bash
#!/bin/bash

# 编译代码(可选)
make build

# 运行测试(假设项目用 pytest)
pytest test_login.py

# 检查测试是否通过
if [ $? -eq 0 ]; then
  exit 0  # 测试通过 → 标记为 good
else
  exit 1  # 测试失败 → 标记为 bad
fi

橡皮鸭调试法 (源于《程序员修炼之道》)

有时候,Bug 并不在于代码本身,而在于我们的思维方式。橡皮鸭调试法(Rubber Duck Debugging)是一种通过向"橡皮鸭"解释代码逻辑,从而发现和解决编程问题的调试方法。

如何使用橡皮鸭调试法:

  1. 准备一个橡皮鸭(或者任何可以"倾听"你解释的对象)。
  2. 逐行向橡皮鸭解释你的代码逻辑,尽量详细地描述每一行代码的作用。
  3. 在解释的过程中,你可能会发现自己在某些地方卡住,或者意识到某些逻辑存在问题。
  4. 通过这种方式,你往往能够自己找到问题的根源。

为什么有效?

  • 语言化思考:将抽象思维转化为具体语言,能强制理清逻辑链条。
  • 简化问题:避免陷入复杂的技术术语,回归问题本质。
  • 打破思维定式:通过"假装教学"的视角,更容易发现盲点。

橡皮鸭调试法的本质是:"如果你不能向一个橡皮鸭解释清楚你的代码,那说明你还没真正理解它。"

使用调试器

调试器是程序员最强大的工具之一,它允许你逐行执行代码,查看变量的值,设置断点,甚至可以在代码运行时修改变量的值。通过使用调试器,你可以高效地跟踪代码的执行过程,找到 Bug 的根源。

但在日常工作中经常看到很多人(以前的我也是)在每个可能出现的 bug 的地方添加各种日志,甚至手动修改一些代码进行调试。不仅导致混乱、效率低,而且还很容易忘记撤回修改的调试代码而导致更多的错误。

这里只简单的说下如何使用调试器(人人应该都会,只是强调多使用调试器进行 Debug,较少随意添加日志的行为):

  1. 设置断点:在你认为可能出现问题的代码行上设置断点。
  2. 逐行执行:启动调试器,逐行执行代码,观察每一步的执行结果。
  3. 查看变量:在调试过程中,查看变量的值,确保它们符合预期。
  4. 修改变量:在调试器中,你可以修改变量的值,测试不同的场景

番外

如果调试时没有看到任何进展,请休息一下。有时,奇迹就会在休息、散步等瞬间的几秒钟内发生。

Released under the MIT License.